# -*- encoding: utf-8 -*-

# Copyright 2010 István Szentandrási
# <etude-music-player@googlegroups.com>

# This file is part of Etude.
#
# Etude is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as 
# published by the Free Software Foundation, either version 3 
# of the License, or (at your option) any later version.
#
# Etude is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Etude. If not, see <http://www.gnu.org/licenses/>.

from . import _

import gobject
import gtk
from threading import Thread
import urllib2 as urllib

import artwriter
import etude.plugins as ep
import queryengine
from artwriter import COVER_SOURCE, MAIN_PROP, EXTRA_PROP
from etude.img import get_pixbuf_from_data, get_data_from_pixbuf, get_pixbuf_of_size

MAX_IMG_SIZE = 600

class Querier(ep.PluginExtra):
    
    _short_name = "Album cover querier"
    _version = "0.0"
    _unique = "AlbumArtQuerier-0.0"
    _title = "AlbumArt"
    _config = {}
    _license = "GPL"

    def __init__(self, control):
        self._interfaces = {'query_album_covers': self.custom_push}
        ep.PluginExtra.__init__(self, control)
        self.client = control.client
        self.query_engine = queryengine.QueryEngine(source_priority=['lastfm',])
        self.art_writer = artwriter.ArtWriter(self.client)

        self.bind(self.client, "e_playback_current_id", self.song_changed)

        self.query_engine.start(CoversThread, threads=2, parent=self)

    def custom_push(self, data):
        """data: id, artist, album
        or id, artist, album, local_image_url"""
        if isinstance(data, tuple):
            if len(data) == 3:
                item = queryengine.QueryItem(*data)
                self.query_engine.queue_push(item)
            elif len(data) == 4:
                item = queryengine.QueryItem(*(data[:3]))
                self.write_arts_local(item, data[3])

    def song_changed(self, client, id):

        nfo = self.client.playback.current_info
        if nfo.has_key(MAIN_PROP):
            return False
        #the song doesn't have a picture yet, or doesn't have a selected one
        if nfo.has_key(EXTRA_PROP):
            extras = nfo[EXTRA_PROP]
            extralist = extras.split(';')
            if len(extralist)>0:
                self.client.medialib.property_set(id, MAIN_PROP, extralist[0],
                        COVER_SOURCE)
                return False
        #lets get images from the internet
        if (nfo.has_key('album') and nfo.has_key('artist') 
                and nfo['album'] != None and nfo['artist'] != None):
            item = queryengine.QueryItem(None, nfo['artist'], nfo['album'])
            self.query_engine.queue_push(item)

    def write_arts_local(self, item, url):
        format = ImageFormat()
        self.write_arts(item, format.add_url(url), overwrite = False)

    def write_arts(self, item, art, overwrite = False):
        def _get_ids(res):
            id_list = res
            self.art_writer.write(art_size, id_list, art_data, overwrite)

        try:
            art_data, art_size = art
        except TypeError:
            return

        id = item.id

        if id == None:
            artist = max(item.artist, '').encode('utf-8')
            album = max(item.album, '').encode('utf-8')
            cl = self.client.collection
            album_and_artist = cl.Intersection(
                    cl.Equals(field='album', value=album, 
                        **{'case-sensitive': 'true'}), 
                    cl.Equals(field='artist', value = artist, 
                        **{'case-sensitive': 'true'}))
            self.client.collection.query_ids(album_and_artist, cb=_get_ids)
        else:
            _get_ids([id,])


    def unload(self):
        ep.PluginExtra.unload(self)
        self.query_engine.stop()


class CoversThread(queryengine.QueryThread, Thread):
    
    def __init__(self, name, engine, parent):
        Thread.__init__(self)
        queryengine.QueryThread.__init__(self, name, engine)
        self.parent = parent
        self.item = None
    
    def run(self):
        self.thread_function(self.handle_results)

    def handle_results(self, item, status, arg=None):
        artist = item.artist
        album = item.album
        
        if status == queryengine.STATUS_FOUND:
            format = ImageFormat()
            for a in arg:
                if a:
                    self.parent.write_arts(item, format.add_url(a))
                print "Art for %s - %s found" % (artist.encode('UTF-8'),
                        album.encode('UTF-8'))
        if status == queryengine.STATUS_NOT_FOUND:
            print "No art for %s - %s anywhere!" % (artist.encode('UTF-8'),
                    album.encode('UTF-8'))
        if status == queryengine.STATUS_STARTING:
            print "Start processing %s - %s with querier %s" % (
                    artist.encode('UTF-8'), album.encode('UTF-8'), arg)


SIZE_UNDEFINED, SIZE_THUMBNAIL = range(0,2)

IMAGE_SIZES = {SIZE_UNDEFINED:((110, -1), (110, -1)), 
                 SIZE_THUMBNAIL:((100, 100), (100, 100))
                }

class ImageFormat(object):

    def __init__(self):
        object.__init__(self)

    def add_url(self, url):
        try:
            img_data = urllib.urlopen(url).read()
        except:
            return None
        try:
            pixb = get_pixbuf_from_data(img_data)
            x,y = (pixb.get_width(), pixb.get_height())
            #check if the albumart is too big
            if max(x,y) > MAX_IMG_SIZE:
                if x>y:
                    pixb = get_pixbuf_from_data(img_data, 
                            (MAX_IMG_SIZE, int(y*MAX_IMG_SIZE*1.0/x)))
                else:
                    pixb = get_pixbuf_from_data(img_data, 
                            (int(x*MAX_IMG_SIZE*1.0/y), MAX_IMG_SIZE))
                x,y = (pixb.get_width(), pixb.get_height())
                img_data = get_data_from_pixbuf(pixb)
            size = self.calculate_size( (x,y))
            return ( img_data, size)
        except gobject.GError:
            return None

    def calculate_size(self, sizes):
        try:
            x, y = sizes
        except Exception:
            return None
        for k, v in IMAGE_SIZES.iteritems():
            if v[0][1] != -1 or v[1][1] != -1:
                if (x >= v[0][0] and x <= v[0][1]
                        and y >= v[1][0] and y <= v[1][1]):
                    return k
            else:
                if x >= v[0][0] and y >= v[1][0]: 
                    return k
 
